package com.fengwk.cv4j.view;

import java.lang.reflect.Array;

import com.fengwk.cv4j.compute.Compute;
import com.fengwk.cv4j.factory.ViewFactoryImpl;
import com.fengwk.cv4j.factory.ViewFactory;
import com.fengwk.support.exception.BaseException;
import com.fengwk.support.util.ArrayUtils;

/**
 * 这是一个抽象的视图实现</br>
 * 实现了视图逻辑处理部分</br>
 * 需由子类实现具体的运算逻辑
 * 
 * @author fengwk
 *
 * @param <T>
 */
public abstract class ViewImpl<T> implements View<T> {
	
	private static final long serialVersionUID = -2750377090414791591L;
	
	/**
	 * 用于树的打印前缀数目
	 */
	private static final int TREE_PRE = 6;
	
	/**
	 * 用于树的打印前缀样式
	 */
	private static final String TREE_PRE_BLANK = "-";
	
	/**
	 * 组成当前运算视图的下层运算视图组
	 */
	private View<T>[] vs;
	
	/**
	 * 运算操作,应当由子类工厂的构造实现{@link ViewFactoryImpl#AbstractComputeViewFactory(Compute)}
	 */
	private Compute<T> compute;
	
	/**
	 * 视图工厂,应继承于视图工厂实现{@link ViewFactoryImpl}
	 */
	private ViewFactory<T> factory;
	
	/**
	 * 当前计算视图的运行结果
	 */
	private T computeT;
	
	/**
	 * 当前计算视图对应的下层计算视图的梯度计算视图
	 */
	private View<T>[] dvs;
	
	/**
	 * 当前视图的父级视图
	 */
	private View<T> parent;
	
	/**
	 * 构造函数
	 * 
	 * @param v1
	 * @param v2
	 * @param compute
	 * @param factory
	 */
	@SuppressWarnings("unchecked")
	protected ViewImpl(Compute<T> compute, ViewFactory<T> factory, View<T>...vs) {
		if (compute == null)
			throw new BaseException("compute == null");
		if (factory == null)
			throw new BaseException("factory == null");
		if (ArrayUtils.isBlank(vs))
			throw new BaseException("ArrayUtils.isBlank(vs)");
		
		this.vs = vs;
		this.compute = compute;
		this.factory = factory;
		
		// 向子视图置入当前视图的链接
		for (View<T> v: vs) {
			if (v instanceof CacheView) 
				((CacheView<T>) v).parent(this);
		}
		
	}
	
	/**
	 * 检查传入的视图构造参数个数是否正确
	 * 
	 * @param limit 限制个数
	 * @param vs
	 */
	@SuppressWarnings("unchecked")
	protected void checkVs(int limit, View<T>...vs) {
	    if (vs == null)
	        throw new BaseException("vs == null");
		if (vs.length != limit)
			throw new BaseException("vs.length != " + limit);
		for (int i = 0; i < vs.length; i ++) {
			if (vs[i] == null)
				throw new BaseException("vs[" + i + "] == null");
		}
	}
	
	@SuppressWarnings("unchecked")
    protected void checkVsMin(int limit, View<T>...vs) {
	    if (vs == null)
            throw new BaseException("vs == null");
        if (vs.length < limit)
            throw new BaseException("vs.length < " + limit);
        for (int i = 0; i < vs.length; i ++) {
            if (vs[i] == null)
                throw new BaseException("vs[" + i + "] == null");
        }
    }
	
	/**
	 * 获取视图组总数量
	 * 
	 * @return
	 */
	protected int len() {
		if (vs == null)
			throw new BaseException("vs == null");
		return vs.length;
	}
	
	/**
	 * 获取第idx个视图
	 * 
	 * @param idx
	 * @return
	 */
	protected View<T> v(int idx) {
		if (idx >= len())
			throw new BaseException("idx >= len()");
		return vs[idx];
	}
	
	/**
	 * 获取所有子视图
	 * 
	 * @return
	 */
	protected View<T>[] vs() {
        return vs;
    }
	
	/**
	 * 获取第idx个视图的运算结果
	 * 
	 * @param idx
	 * @return
	 */
	protected T t(int idx) {
		if (idx >= len())
			throw new BaseException("idx >= len()");
		View<T> v = v(idx);
		if (v == null)
			throw new BaseException("v(" + idx + ") == null");
		return v.compute();
	}
	
	/**
     * 获取所有视图的运算结果
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    protected T[] ts() {
        if (len() <= 0)
            throw new BaseException("len() <= 0");
        T t = t(0);
        Object ts = Array.newInstance(t.getClass(), len());
        Array.set(ts, 0, t);
        for (int i = 1; i < len(); i ++) 
            Array.set(ts, i, t(i));
        return (T[]) ts;
    }
	
	/**
	 * 获取运算操作
	 * 
	 * @return
	 */
	protected Compute<T> c() {
		return compute;
	}
	
	/**
	 * 获取视图工厂
	 * 
	 * @return
	 */
	protected ViewFactory<T> f() {
		return factory;
	}
	
	@Override
	public T compute() {
		if (computeT != null)
			return computeT;
		return compute0();
	}

	@Override
	public View<T> gradient(View<T> v) {
		if (v == this)
			return f().of(1, computeT);
		View<T> sum = null;
		for (int i = 0; i < len(); i ++) {
			View<T> vi = v(i);

			if (vi.search(v)) {
				// 链式法则
				View<T> dvi = f().mul(vi.gradient(v), gradient(i));
				if (sum == null)
					sum = dvi;
				else
					sum = f().add(sum, dvi);
			}
			
		}
		if (sum == null)
			throw new BaseException("can not gradient to v " + v);
		
		return sum;
	}
	
	/**
	 * 返回该运算图上第idx个元素这条链路的导数视图
	 * 
	 * @param idx
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected View<T> gradient(int idx) {
		if (dvs == null)
			dvs = (View<T>[]) new View<?>[len()];
		View<T> dv = dvs[idx];
		if (dv == null) {
			dv = gradient0(idx);
			dvs[idx] = dv;
		}
		return dv;
	}
	
	/**
	 * 由子类实现,返回运算结果
	 * 
	 * @return
	 */
	protected abstract T compute0();
	
	/**
	 * 由子类实现,返回该运算图上第idx个元素这条链路的导数视图
	 * 
	 * @param idx
	 * @return
	 */
	protected abstract View<T> gradient0(int idx);

	@Override
	public String tree() {
		return tree(0);
	}
	
	private String tree(int deep) {
		StringBuilder sb = new StringBuilder();
		sb.append(preBlank(deep)).append(toString()).append("\n");
		for (View<T> v: vs()) {
			if (v instanceof ViewImpl)
				sb.append(((ViewImpl<T>) v).tree(deep + 1));
			else 
				sb.append(preBlank(deep + 1)).append(v.tree());
		}
		return sb.toString();
	}
	
	private String preBlank(int deep) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < deep * TREE_PRE; i ++)
			sb.append(TREE_PRE_BLANK);
		return sb.toString();
	}

	@Override
	public void parent(View<T> v) {
		this.parent = v;
	}

	@Override
	public void clear() {
		computeT = null;
		dvs = null;
		if (parent != null && parent instanceof CacheView)
			parent.clear();
	}

	@Override
	public boolean search(View<T> v) {
		if (v == this)
			return true;
		for (View<T> s: vs()) {
			if (s.search(v))
				return true;
		}
		return false;
	}
	
}
